home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Wayzata's Best of Shareware PC/Windows 1
/
Wayzata's Best of Shareware for PC-Windows - Release 1 - Wayzata Technology (1993).iso
/
mac
/
DOS
/
GRAPHICS
/
RAYSH386
/
GEOM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-30
|
10KB
|
445 lines
/*
* object.c
*
* Copyright (C) 1989, 1991, Craig E. Kolb
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
* $Id: geom.c,v 4.0.1.1 91/09/29 15:43:15 cek Exp Locker: cek $
*
* $Log: geom.c,v $
* Revision 4.0.1.1 91/09/29 15:43:15 cek
* patch1: GeomBounds now inflates bounds by EPSILON.
*
* Revision 4.0 91/07/17 14:37:47 kolb
* Initial version.
*
*/
#include "geom.h"
#include "list.h"
#include "sampling.h"
static void GeomBounds(), GeomBoundsAnimated();
void GeomResolveAssoc(); /* probably static */
Geom *
GeomCreate(objptr, methods)
GeomRef objptr;
Methods *methods;
{
Geom *obj;
if (objptr == (GeomRef)NULL)
return (Geom *)NULL;
obj = (Geom *)share_calloc(1, sizeof(Geom));
obj->obj = objptr;
obj->methods = methods;
obj->animtrans = FALSE;
obj->trans = obj->transtail = (Trans *) NULL;
obj->frame = -1; /* impossible value */
BoundsInit(obj->bounds);
#ifdef SHAREDMEM
/*
* If the counter is in shared memory, processes will
* be modifying it left-and-right. So, we cheat and
* make counter a pointer to a non-shared location and
* store the value there.
*/
new->counter = (unsigned long *)RayMalloc(sizeof(unsigned long));
*new->counter = 0;
#endif
return obj;
}
/*
* Return a copy of the given object.
* Note that surface, texturing, and transformation information
* is copied by reference.
*/
Geom *
GeomCopy(obj)
Geom *obj;
{
Geom *new;
new = GeomCreate(obj->obj, obj->methods);
/* Share texturing, name, #prims, surface info */
new->name = obj->name;
new->texture = obj->texture;
new->surf = obj->surf;
new->prims = obj->prims;
new->trans = obj->trans;
new->animtrans = obj->animtrans;
new->transtail = obj->transtail;
/* copy bounds */
BoundsCopy(obj->bounds, new->bounds);
return new;
}
/*
* Report bounding box and number of primitives in object.
*/
void
AggregatePrintInfo(obj, fp)
Geom *obj;
FILE *fp;
{
if (fp) {
if (obj->name && obj->name[0])
fprintf(fp,"%s \"%s\":\n", GeomName(obj), obj->name);
else
fprintf(fp,"%s:\n", GeomName(obj));
if (!UNBOUNDED(obj))
BoundsPrint(obj->bounds, fp);
fprintf(fp,"\t%lu primitive%c\n",obj->prims,
obj->prims == 1 ? ' ' : 's');
}
}
/*
* Convert the given object from a linked list of objects to
* the desired aggregate type.
*/
int
AggregateConvert(obj, objlist)
Geom *obj, *objlist;
{
if (!IsAggregate(obj)) {
RLerror(RL_ABORT, "A %s isn't an aggregate.\n",
GeomName(obj));
return 0;
}
return (*obj->methods->convert)(obj->obj, objlist);
}
/*
* This should really be called
* GeomInitialize
* or something.
*/
void
GeomComputeBounds(obj)
Geom *obj;
{
if (obj->frame == Sampling.framenum)
return;
if (!obj->animtrans) {
/*
* If it isn't animated,
* just compute bbox directly
*/
GeomBounds(obj, obj->bounds);
} else {
/*
* Animated things are gonna get a bbox
* which is large enough to enclose all
* the places where the object goes.
*/
GeomBoundsAnimated(obj);
}
/*
* Enlarge by EPSILON in each direction just to
* be on the safe side.
*/
obj->bounds[LOW][X] -= EPSILON;
obj->bounds[HIGH][X] += EPSILON;
obj->bounds[LOW][Y] -= EPSILON;
obj->bounds[HIGH][Y] += EPSILON;
obj->bounds[LOW][Z] -= EPSILON;
obj->bounds[HIGH][Z] += EPSILON;
/*
* Mark the fact that that the obj is initialized
* for this frame.
*/
obj->frame = Sampling.framenum;
obj->counter = 0;
}
static void
GeomBoundsAnimated(obj)
Geom *obj;
{
int i, m;
Float newbounds[2][3];
Float window, subwindow, jitter, subjitter;
/*
* For each possible screen sample,
* choose TIME_SUB_SAMPLES times and recompute the
* bounds of obj at that time,
* expanding the computed bounding box appropriately.
*/
BoundsInit(obj->bounds);
jitter = Sampling.shutter / Sampling.totsamples;
subjitter = jitter / (Float)TIME_SUB_SAMPLES;
window = Sampling.starttime;
for (i = 0; i < Sampling.totsamples; i++, window += jitter) {
subwindow = window;
for (m = 0; m < TIME_SUB_SAMPLES; m++, subwindow += subjitter) {
/*
* Set the current time.
*/
TimeSet(subwindow + subjitter*nrand());
/*
* Resolve the objects geometric associations
*/
GeomResolveAssoc(obj);
/*
* Compute bounds and expand current bounds.
*/
GeomBounds(obj, newbounds);
BoundsEnlarge(obj->bounds, newbounds);
}
}
/*
* Also sample at time extremes, as for many
* movements, extremes occur at beginning/end times.
*/
TimeSet(Sampling.starttime);
GeomResolveAssoc(obj);
GeomBounds(obj, newbounds);
BoundsEnlarge(obj->bounds, newbounds);
TimeSet(Sampling.starttime + Sampling.shutter);
GeomResolveAssoc(obj);
GeomBounds(obj, newbounds);
BoundsEnlarge(obj->bounds, newbounds);
}
void
GeomResolveAssoc(obj)
Geom *obj;
{
/*
* PrimResolveAssoc(obj);
*/
TransResolveAssoc(obj->trans);
}
/*
* Set "bounds" of object to be the extent of the primitive.
*/
static void
GeomBounds(obj, bounds)
Geom *obj;
Float bounds[2][3];
{
Trans *trans;
if (!obj || !obj->methods->bounds)
RLerror(RL_ABORT, "Can't compute bounds of \"%s\".\n",
GeomName(obj));
(*obj->methods->bounds) (obj->obj, bounds);
bounds[LOW][X] -= EPSILON;
bounds[LOW][Y] -= EPSILON;
bounds[LOW][Z] -= EPSILON;
bounds[HIGH][X] += EPSILON;
bounds[HIGH][Y] += EPSILON;
bounds[HIGH][Z] += EPSILON;
if (obj->trans) {
for (trans = obj->trans; trans; trans = trans->next)
BoundsTransform(&trans->trans, bounds);
}
}
char *
GeomName(obj)
Geom *obj;
{
if (obj->methods->name)
return (*obj->methods->name)();
return "unknown";
}
void
GeomStats(obj, tests, hits)
Geom *obj;
unsigned long *tests, *hits;
{
if (obj && obj->methods->stats)
(*obj->methods->stats)(tests, hits);
else {
*tests = *hits = 0;
}
}
/*
* Push an object onto the head of the given stack, returning
* the new head.
*/
GeomList *
GeomStackPush(obj, list)
Geom *obj;
GeomList *list;
{
GeomList *new;
/*
* Pretty simple.
* Make new element point to old head and return new head.
*/
new = (GeomList *)RayMalloc(sizeof(GeomList));
new->obj = obj;
new->next = list;
return new;
}
/*
* Pop the topmost object off of the given stack, returning the new head.
* The old head is freed, but the object it points to is not.
*/
GeomList *
GeomStackPop(list)
GeomList *list;
{
GeomList *ltmp;
ltmp = list->next; /* Save new head. */
free((voidstar)list); /* Free old head. */
return ltmp; /* Return new head. */
}
Methods *
MethodsCreate()
{
return (Methods *)share_calloc(1, sizeof(Methods));
}
/*
* Call appropriate routine to compute UV and, if non-null,
* dpdu and dpdv at given point on the given primitive. The
* normal is used to facilitate computation of u, v, and the
* partial derivatives.
*/
void
PrimUV(prim, pos, norm, uv, dpdu, dpdv)
Geom *prim;
Vector *pos, *norm, *dpdu, *dpdv;
Vec2d *uv;
{
/*
* Call appropriate inverse mapping routine
*/
if (prim->methods->uv == NULL) {
uv->u = uv->v = 0.;
if (dpdu) {
dpdu->y = dpdu->z = 0.;
dpdu->x = 1.;
}
if (dpdv) {
dpdv->x = dpdv->z = 0.;
dpdv->y = 1.;
}
} else
(*prim->methods->uv)(prim->obj,pos,norm,uv,dpdu,dpdv);
}
int
PrimNormal(prim, pos, norm, gnorm)
Geom *prim;
Vector *pos, *norm, *gnorm;
{
/*
* Call appropriate normal routine
*/
return (*prim->methods->normal) (prim->obj, pos, norm, gnorm);
}
int
PrimEnter(obj, ray, mind, hitd)
Geom *obj;
Ray *ray;
Float mind, hitd;
{
/*
* Call appropriate enter/leave routine
*/
if (obj->methods->enter == NULL) {
Vector pos, nrm, gnrm;
/*
* Sleazy method: Use hit point, find normal
* and take dot prod with ray
*/
VecAddScaled(ray->pos, hitd, ray->dir, &pos);
PrimNormal(obj, &pos, &nrm, &gnrm);
return dotp(&ray->dir, &gnrm) < 0.0;
}
else
return (*obj->methods->enter) (obj->obj, ray, mind, hitd);
}
/*
* Walk through a linked-list of objects. If the object is unbounded,
* unlink it it from the list and add it to the 'unbounded' list.
* If the object is bounded, enlarge the given bounding box if
* necessary. Return pointer to unbounded list.
*/
Geom *
GeomComputeAggregateBounds(bounded, unbounded, bounds)
Geom **bounded, *unbounded;
Float bounds[2][3];
{
Geom *ltmp, *prev, *nextobj;
BoundsInit(bounds);
prev = (Geom *)0;
for (ltmp = *bounded; ltmp; ltmp = nextobj) {
nextobj = ltmp->next;
GeomComputeBounds(ltmp);
if (UNBOUNDED(ltmp)) {
/*
* Geom is unbounded -- unlink it...
*/
if (prev)
prev->next = ltmp->next;
else
*bounded = ltmp->next;
/*
* And add it to unbounded object list.
*/
ltmp->next = unbounded;
unbounded = ltmp;
} else {
/*
* Geom is bounded.
*/
BoundsEnlarge(bounds, ltmp->bounds);
prev = ltmp;
}
}
return unbounded;
}
/*
* Find 'highest' animated object on the hitlist.
*/
int
FirstAnimatedGeom(hitlist)
HitList *hitlist;
{
int i;
for (i = hitlist->nodes -1; i; i--)
/*
* If object itself is animated, have
* to check other flag, too...
*/
if (hitlist->data[i].obj->animtrans)
return i;
return 0;
}